<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="utf-8">
		<title>Canvas签名</title>
		<style>
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
			}
			body {
				height: 100vh;
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
			}
		</style>
	</head>

	<body>
		<div style="margin: 0px 0px;">
			<canvas id="canvas" width="500" height="300" style="width: 500px; height: 300px; background: #eee;"></canvas>
			<div style="width: 100%;">
				<button onclick="handleClear(event)">清除</button>
				<button onclick="handleRevoke(event)">撤销</button>
				<button onclick="handleReform(event)">重做</button>
				<button onclick="handleSave(event)">保存</button>
			</div>
		</div>
		<img id="prevImg" alt="" style="margin-top: 50px; width: 500px; height: 300px; border: 1px solid #eee;">
	</body>
	
	<script>
		const canvas = document.querySelector('#canvas')
		const img = document.querySelector('#prevImg')
		const ctx = canvas.getContext('2d')
		console.dir(ctx)
		
		ctx.lineWidth = 2
		ctx.lineCap = 'round'
		ctx.lineJoin = 'round'
		ctx.strokeStyle = 'red'
		
		let scaleX = canvas.width / canvas.offsetWidth
		let scaleY = canvas.height / canvas.offsetHeight
		
		let points = []
		let pindex = 0
		let flag = false
		canvas.addEventListener('mousedown', function(e) {
			// console.log(e)
			ctx.beginPath()
			ctx.moveTo(e.offsetX * scaleX, e.offsetY * scaleY)
			canvas.addEventListener('mousemove', drawLine)
		})
		canvas.addEventListener('mouseup', function(e) {
			canvas.removeEventListener('mousemove', drawLine)
			pindex += 1
			// console.log(points, pindex)
		})
		canvas.addEventListener('mouseleave', function(e) {
			canvas.removeEventListener('mousemove', drawLine)
		})
		
		// 绘制
		function drawLine(e) {
			ctx.lineTo(e.offsetX * scaleX, e.offsetY * scaleY)
			ctx.stroke()
			
			if (flag) {
				flag = false
				points = points.slice(0, pindex)
			}
			points[pindex] = points[pindex] || []
			points[pindex].push({ x: e.offsetX * scaleX, y: e.offsetY * scaleY })
		}
		// 清除
		function handleClear(e) {
			// console.log(e)
			ctx.clearRect(0, 0, canvas.width, canvas.height)
			points = []
			img.setAttribute('src', ' ')
		}
		// 撤销
		function handleRevoke(e) {
			// console.log(e)
			if (pindex <= 0) return
			ctx.clearRect(0, 0, canvas.width, canvas.height)
			pindex -= 1
			const copyPoints = points.filter((item, index) => index < pindex)
			for (let i = 0; i < copyPoints.length; i++) {
				ctx.beginPath()
				for (let j = 0; j < copyPoints[i].length; j++) {
					ctx.lineTo(copyPoints[i][j].x, copyPoints[i][j].y)
					ctx.stroke()
				}
			}
			flag = true
		}
		// 重做
		function handleReform(e) {
			// console.log(e)
			if (pindex >= points.length) return
			ctx.beginPath()
			for (let i = 0; i < points[pindex].length; i++) {
				ctx.lineTo(points[pindex][i].x, points[pindex][i].y)
				ctx.stroke()
			}
			pindex += 1
		}
		// 保存
		function handleSave(e) {
			// console.log(e)
			const dataURL = canvas.toDataURL('image/png', 1)
			img.setAttribute('src', dataURL)
			
			const a = document.createElement('a')
			a.href = dataURL
			a.download = `电子签名_${Date.now()}.png`
			a.click()
		}
	</script>
</html>